package com.zhangyang.esper.epl;

import com.espertech.esper.client.*;
import junit.framework.TestCase;


import java.util.*;

/**
 * @author Dell
 * @Title:
 * @Description: 请写注释类
 * @date 2023/2/27
 */
public class EsperDynamicTypeExample extends TestCase {


    public  void testDynamicType() {
        // create Esper engine
        EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();

        // create dynamic event type based on input data
        Map<String, Object> eventData = new HashMap<>();
        eventData.put("field1", "value1");
        eventData.put("field2", 2);
        eventData.put("field3", 3L);
        eventData.put("field4", 4.0);
        eventData.put("field5", true);

        Configuration configuration = new Configuration();
        configuration.addEventTypeAutoName("dynamicEventType");

        EPServiceProvider epServiceProvider = EPServiceProviderManager.getDefaultProvider(configuration);

        // send event to Esper engine and execute EPL statement
        epServiceProvider.getEPRuntime().sendEvent(eventData, "dynamicEventType");

        String epl = "select * from dynamicEventType";
        epServiceProvider.getEPAdministrator().createEPL(epl).addListener((newData, oldData) -> {
            for (EventBean eventBean : newData) {
                System.out.println(eventBean.getUnderlying());
            }
        });
    }

    public  void testDynamicType2() {
        // create Esper engine configuration
        Configuration config = new Configuration();
        config.getEngineDefaults().getExecution().setPrioritized(true);

        // create Esper engine instance
        EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);

        // create event sender
        EPRuntime runtime = epService.getEPRuntime();

        // send sample events with different field types
//        runtime.sendEvent(createEvent(Map.of("field1", "value1", "field2", 123, "field3", true)));
//        runtime.sendEvent(createEvent(Map.of("field1", "value2", "field2", 456, "field3", false)));
//        runtime.sendEvent(createEvent(Map.of("field1", "value3", "field2", 789, "field3", true)));

        // create and register dynamic event type
        EPAdministrator admin = epService.getEPAdministrator();
        Map<String, Object> eventData = new HashMap<>();

        // iterate over all events and extract field names and types
//        for (EventBean eventBean : runtime.snapshot(new com.espertech.esper.client.time.ZeroTimePolicy())) {
//            Map<String, Object> eventMap = (Map<String, Object>) eventBean.getUnderlying();
//
//            for (Map.Entry<String, Object> entry : eventMap.entrySet()) {
//                String fieldName = entry.getKey();
//                Object value = entry.getValue();
//
//                // check if field already exists in event type
//                if (!eventData.containsKey(fieldName)) {
//                    // add new field to event type
//                    eventData.put(fieldName, value != null ? value.getClass() : Object.class);
//                }
//            }
//        }

//        EventType dynamicEventType = admin.getConfiguration().getEventTypeFactory().createObjectType("dynamicEventType", eventData);
//        admin.getConfiguration().addEventType("dynamicEventType", dynamicEventType);

        // create EPL statement to query the dynamic event type
        String epl = "select * from dynamicEventType";
        EPStatement statement = admin.createEPL(epl);

        // add listener to handle query results
        statement.addListener((newData, oldData) -> {
            for (EventBean eventBean : newData) {
                System.out.println(eventBean.getUnderlying());
            }
        });
    }

    // helper method to create a Map event with unknown field types
    private static Map<String, Object> createEvent(Map<String, Object> fieldData) {
        Map<String, Object> event = new HashMap<>();
        event.putAll(fieldData);
        return event;
    }

    public  void testDynamicType3() {
// create Esper engine configuration
        Configuration configuration = new Configuration();
        configuration.addEventTypeAutoName("dynamicEventType");

        // create Esper engine instance
        EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(configuration);

        // create example input data with dynamic field names and types
        Map<String, Object> eventData1 = new HashMap<String, Object>();
        eventData1.put("field1", "value1");
        eventData1.put("field2", 2);

        Map<String, Object> eventData2 = new HashMap<String, Object>();
        eventData2.put("field3", 3.0);
        eventData2.put("field4", true);

        // create dynamic event type based on input data
        Set<String> fieldNames = new HashSet<String>();
        for (Map<String, Object> eventData : Arrays.asList(eventData1, eventData2)) {
            fieldNames.addAll(eventData.keySet());
        }

        Map<String, Object> eventMap = new HashMap<String, Object>();
        for (String fieldName : fieldNames) {
            List<Object> fieldValues = new ArrayList<Object>();
            for (Map<String, Object> eventData : Arrays.asList(eventData1, eventData2)) {
                if (eventData.containsKey(fieldName)) {
                    fieldValues.add(eventData.get(fieldName));
                }
            }

            Class<?> fieldType = determineFieldType(fieldValues);
            eventMap.put(fieldName, fieldType);
        }

        String eventTypeName = "dynamicEventType";
        EPAdministrator admin = epService.getEPAdministrator();
        if (!admin.getConfiguration().isEventTypeExists(eventTypeName)) {
            EventType dynamicEventType = admin.getConfiguration().getEventType(eventTypeName);
//            admin.getConfiguration().addEventType(eventTypeName, dynamicEventType);
        }

        // send input data to Esper and execute EPL statement
        EPRuntime runtime = epService.getEPRuntime();
        for (Map<String, Object> eventData : Arrays.asList(eventData1, eventData2)) {
            runtime.sendEvent(eventData, eventTypeName);
        }

        String epl = "select * from " + eventTypeName;
        EPStatement statement = admin.createEPL(epl);
        statement.addListener((newData, oldData) -> {
            for (EventBean eventBean : newData) {
                System.out.println(eventBean.getUnderlying());
            }
        });
    }

    private static Class<?> determineFieldType(List<Object> values) {
        Class<?> fieldType = null;
        for (Object value : values) {
            if (value != null) {
                fieldType = value.getClass();
                break;
            }
        }

        if (fieldType == null) {
            // if all values are null, use String as default type
            fieldType = String.class;
        }

        return fieldType;
    }

    public  void testDynamicEvent() throws InterruptedException {
        Configuration configuration = new Configuration();
        EPServiceProvider epServiceProvider = EPServiceProviderManager.getDefaultProvider(configuration);

        String[] headers = {"name", "age", "gender"};
        Object[] eventData = {null, null, null};
        Map<String, Object> event = new HashMap<>();
        for (int i = 0; i < headers.length; i++) {
            event.put(headers[i], eventData[i]);
        }

//        configuration.addEventTypeAutoName("DynamicEventType", event);
        EPStatement epStatement = epServiceProvider.getEPAdministrator().createEPL("select * from DynamicEventType");

        epStatement.addListener((newData, oldData) -> {
            System.out.println(newData[0].getUnderlying());
        });

        for (int i = 0; i < 10; i++) {
            epServiceProvider.getEPRuntime().sendEvent(event);
            Thread.sleep(1000);
        }
    }
}
